/**
 * \file I3ClientContext.h
 * \brief Declares some of the context information associated with the i3 overlay.  Most of the context information is incorporated by including a pointer to
 * cl_context object of the real i3 API.
*/

#ifndef I3_CLIENT_CONTEXT_CPP_H
#define I3_CLIENT_CONTEXT_CPP_H

#include "OCD_include.h"

extern "C" {

    #include "i3_client.h"
    #include "i3_config.h"
}
class I3OverlayNetwork;
class I3Trigger;
class TimerEvent;

//TODO rename in better way
/** The largest port number that can be used for binding the proxy, if custom port not specified. */
#define MAX_PORT_NUM 11000
/** The smallest port number that can be used for binding the proxy, if custom port not specified. */
#define MIN_PORT_NUM 10000

class I3ClientContext {

private:
    /** The I3 context of this I3Instance */
    cl_context *g_ctx;
    cl_buf      *clb;

    /** 
      * Pointer to the i3 overlay associated with this context. 
      */
    I3OverlayNetwork *i3Overlay;

    /* duplicate data: (1) create a buffer p of size len, (2) copy pdata
    * to p, and (3) return p
    */ 
    void *cl_duplicate_data(void *pdata, unsigned int len);

    
    /** 
      * This is a temporary character array needed while printing out stuff to screen.
      */
    char tmpBuf[MAX_PRINT_BUF];
public:
    
    I3ClientContext(I3OverlayNetwork *, const char*);
    

    
    void receivedPacketFromOverlay();

    int getOverlayPktRcvFD();
    int getOverlayPktRcvTCPFD();
    bool isTCPSupported();

    void reInsertTrigger(I3Trigger *trig);

    void sendToStack(i3_stack *, cl_buf*, uint8_t);
    cl_trigger *createTrigger(ID *id, uint16_t prefix_len, Key *key, uint8_t flags, int *rc);

    cl_trigger* createTriggerStack (
            ID *id, uint16_t prefix_len, string stack, uint8_t flags, int *retCode);

    void destroyTrigger (cl_trigger* t);

    int insertTrigger(I3Trigger*, uint8_t flags);
    
    int registerTriggerCallback(cl_trigger *ctr, uint16_t cbk_type, 
            void (*fun)(cl_trigger*, void *data, void *fun_ctx), 
            void *fun_ctx);

    int registerContextCallback(uint16_t cbk_type, 
            void (*fun)(void* ctx_data, void *data, void *fun_ctx), 
            void *fun_ctx);

    void doAddressChangeCheck();
    void doServerUpdate();

    int getNumKnownI3Servers();
    
    void timeoutAckInsert(I3Trigger* trig);
    void timeoutAckRefresh(I3Trigger* trig);
   
    void addTimeoutTriggerAck(I3Trigger* trig);
    void addTimeoutTriggerRefresh(I3Trigger* trig);
    
    void addTimerEvent(TimerEvent *);

    bool usePing();

    bool isTCPInitOk();

	void closeAllSockets();

    friend class I3OverlayNetwork;

    friend class Proxy; //HACK
};



#endif // I3_CLIENT_CONTEST_H
